package com.inspur.edp.common.type.utils;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.inspur.edp.common.type.exception.JsonException;

import java.io.IOException;

/**
 * @author lizhaorui
 * @description TODO
 * @date 2024/7/27 17:02
 */
public class JsonPropUtil {

    public static ArrayNode getArrayAndValidate(JsonNode jObj, String propName) {
        ArrayNode arrayNode = getValueAndValidate(jObj, propName, ArrayNode.class);
        if (arrayNode.size() == 0) {
            throw new JsonException(String.format("property %s can be empty.", propName));
        }
        return arrayNode;
    }

    public static String getStringAndValidate(JsonNode jObj, String propName) {
        return getValueAndValidate(jObj, propName, String.class);
    }

    public static ObjectNode getObjectNodeAndValidate(JsonNode jObj, String propName) {
        return getValueAndValidate(jObj, propName, ObjectNode.class);
    }

    public static <T> T getValueAndValidate(JsonNode jObj, String propName, Class<T> tClass) {
        T t = getPropValue(jObj, propName, tClass);
        if (t == null) {
            throw new JsonException(String.format("property [%s] can not be empty.", propName));
        }
        return t;
    }

    public static <T> T getPropValue(JsonNode jObj, String propName, Class<T> tClass) {
        if (jObj == null) {
            return null;
        }
        JsonNode propNode = jObj.get(propName);
        if (propNode == null) {
            return null;
        }
        try {
            return MAPPER.treeToValue(propNode, tClass);
        } catch (JsonProcessingException e) {
            throw new JsonException("Error obtaining property:", e);
        }
    }

    public static String getPropValueAsString(JsonNode jObj, String propName) {
        return getPropValue(jObj, propName, String.class);
    }


    public static <T> T convert(JsonNode jsonNode, Class<T> tClass) {
        if (jsonNode == null) {
            return null;
        }
        try {
            return MAPPER.treeToValue(jsonNode, tClass);
        } catch (JsonProcessingException e) {
            throw new JsonException("Attribute conversion error:", e);
        }
    }


    public static <T> T getPropValue(JsonNode jObj, String propName, TypeReference<T> refer) {

        if (jObj == null) {
            return null;
        }
        JsonNode propNode = jObj.get(propName);
        if (propNode == null) {
            return null;
        }
        return MAPPER.convertValue(propNode, refer);
    }

    public static Boolean isExistsProp(JsonNode jObj, String propName) {
        if (jObj == null) {
            return false;
        }
        return jObj.has(propName);
    }

    public static void setPropValue(JsonNode jobj, String propName, Object t) {
        ObjectNode objNode = (ObjectNode) jobj;
        if (t instanceof JsonNode) {
            objNode.set(propName, (JsonNode) t);
        } else {
            objNode.set(propName, MAPPER.valueToTree(t));
        }
    }

    public static void addItemToArray(ArrayNode arrayNode, Object t) {
        arrayNode.add(MAPPER.valueToTree(t));
    }


    public static ArrayNode addEmptyArray(JsonNode jobj, String propName) {
        ArrayNode arrayNode = MAPPER.createArrayNode();
        ObjectNode objNode = (ObjectNode) jobj;
        objNode.set(propName, arrayNode);
        return arrayNode;
    }

    public static <T> T deserialize(String string, Class<T> type) {

        try {
            return MAPPER.readValue(string, type);
        } catch (IOException e) {
            throw new JsonException("Error while deserializing:", e);
        }
    }

    public static String serialize(Object object) {

        try {
            return MAPPER.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new JsonException("Error while serializing:", e);
        }
    }


    private static final ObjectMapper MAPPER;

    static {
        MAPPER = new ObjectMapper();
        // 忽略不识别的字段
        MAPPER.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);

        // 允许没有引号包裹的字段
        MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

        // 当遇到不能识别的属性时，正常执行
        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        // 忽略字段大小写
        MAPPER.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);

        // 允许JSON字符串包含非JSON标准控制字符
        MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);

        MAPPER.registerModule(new JavaTimeModule());

    }

}
